package filters

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"math/rand"
	"net/http"
	"strconv"
	"time"

	"cashew.com/cashew_common/configs"
	"github.com/beego/beego/v2/core/logs"
	beecontext "github.com/beego/beego/v2/server/web/context"
)

// 假设已知合法服务器名称的哈希值列表
func FilterCode(ctx *beecontext.Context) {

	isOpen := configs.FilterCodeIsOpen

	if isOpen == 0 {
		return
	}

	//限制请求必须是post请求且格式必须是json
	if ctx.Input.Method() != "POST" {
		ctx.Output.SetStatus(http.StatusMethodNotAllowed)
		return
	}

	contentType := ctx.Input.Header("Content-Type")
	if contentType != "application/json" {
		ctx.Output.SetStatus(http.StatusUnsupportedMediaType)
		return
	}

	body := string(ctx.Input.RequestBody)
	logs.Debug("FilterCode-body:", body)

	if body == "" {
		return
	}

	var reqData map[string]interface{}
	err := json.Unmarshal([]byte(body), &reqData)
	if err != nil {
		logs.Error("请求体JSON解析失败: %v", err)
		requestValidateFail(ctx)
		return
	}

	bodyBytes, err := json.Marshal(reqData)
	if err != nil {
		return
	}
	logs.Info("FilterCode 请求体数据bodyBytes: %s", string(bodyBytes))

	authCode := ctx.Input.Header("AuthCode")
	serverCode := ctx.Input.Header("ServerCode")

	logs.Debug("FilterCode-authCode:", authCode)
	//logs.Debug("FilterCode-serverCode:", serverCode)

	if authCode == "" {
		requestValidateFail(ctx)
		return
	}

	// 计算签名
	codeKey := configs.FilterCodeKey
	calculatedAuthCode := GenerateAuthCode(string(bodyBytes), codeKey)

	// 校验 authCode
	if calculatedAuthCode != authCode {
		logs.Debug("filterCode validate failed!")
		requestValidateFail(ctx)
		return
	}

	// 校验 serverCode
	timeLimit := configs.FilterCodeTimeLimit

	if !validateServerCode(serverCode, codeKey, timeLimit) {
		logs.Debug("filterCode validate failed!")
		requestValidateFail(ctx)
		return
	}

	logs.Debug("filterCode validate success!")

}

func GenerateAuthCode(body string, codeKey string) string {
	body += codeKey // 最后加上 anthKey

	// 计算 MD5
	hash := md5.Sum([]byte(body))

	//将哈希值转换为十六进制字符串
	return hex.EncodeToString(hash[:])
}

func GenerateServerCode(serverName string, codeKey string) string {
	// 获取当前时间戳（秒）
	now := time.Now().Unix()
	timestampHex := fmt.Sprintf("%x", now)

	// 生成一个简单的随机数以字符串的形式加入
	randomNum := rand.Intn(1000) // 假设范围是0-999
	randomStr := fmt.Sprintf("%03d", randomNum)

	// 将时间戳和随机数拼接成字符串
	dataToHash := timestampHex + randomStr + serverName

	byteDataToHash, err := encryptAES([]byte(codeKey), []byte(dataToHash))
	if err != nil {
		logs.Warn("加密出错:%v", err)
	}
	return hex.EncodeToString(byteDataToHash)
}

func validateServerCode(serverCode string, codeKey string, timeLimit int64) bool {
	// 解析authCode
	// 提取时间戳部分（简单示例，实际可能需要更复杂的解析）
	decoded, err := hex.DecodeString(serverCode)
	if err != nil {
		logs.Warn("hex.DecodeString(%s):%v", serverCode, err)
		return false
	}
	decryptedText, err := decryptAES([]byte(codeKey), decoded)
	if err != nil {
		logs.Warn("解密出错:%v", err)
		return false
	}
	logs.Debug("FilterCode-decryptedText:", string(decryptedText))

	// 确定时间戳的长度，要与生成时一致
	timestampHexLength := 8 // 例如，假设使用8位16进制
	timestampBytes := decryptedText[:timestampHexLength]
	timestamp, err := strconv.ParseInt(string(timestampBytes), 16, 64) // 注意16进制解析
	if err != nil {
		logs.Warn("strconv.ParseInt(%s):%v", string(timestampBytes), err)
		return false
	}
	logs.Debug("FilterCode-timestamp:", timestamp)

	now := time.Now().Unix()

	// 验证时间戳是否在有效期内
	if now-timestamp > timeLimit {
		logs.Warn("过期的 serverCode")
		return false
	}

	// 验证服务器名称是否合法
	serverName := configs.FilterCodeServerName
	calculatedServerName := string(decryptedText[timestampHexLength+3:])
	logs.Debug("FilterCode-calculatedServerName:", calculatedServerName)
	if calculatedServerName != serverName {
		logs.Warn("非法的服务器名称")
		return false
	}

	return true
}

func encryptAES(key []byte, plaintext []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	// 使用PKCS7填充（如果需要）
	paddedPlaintext := PKCS7Padding(plaintext, block.BlockSize())
	ciphertext := make([]byte, len(paddedPlaintext))
	// 创建CBC模式的分组密码模式
	iv := make([]byte, block.BlockSize())
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(ciphertext, paddedPlaintext)
	return ciphertext, nil
}

func decryptAES(key []byte, ciphertext []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	iv := make([]byte, block.BlockSize())
	mode := cipher.NewCBCDecrypter(block, iv)
	plaintext := make([]byte, len(ciphertext))
	mode.CryptBlocks(plaintext, ciphertext)
	// 去除PKCS7填充（如果有）
	unpaddedPlaintext, err := PKCS7Unpadding(plaintext)
	if err != nil {
		return nil, err
	}
	return unpaddedPlaintext, nil
}

// PKCS7填充函数
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

// PKCS7去填充函数
func PKCS7Unpadding(plaintext []byte) ([]byte, error) {
	length := len(plaintext)
	unpadding := int(plaintext[length-1])
	if unpadding > length {
		return nil, fmt.Errorf("无效的填充")
	}
	return plaintext[:length-unpadding], nil
}
